using RAG.Domain.Entities.App;
using RAG.Domain.Repositories;
using RAG.Domain.Services;
using Microsoft.Extensions.Logging;
using RAG.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;

namespace RAG.Infrastructure.Services;

/// <summary>
/// 数据初始化服务 - 用于添加测试数据
/// </summary>
public class DataSeederService
{
    private readonly IKnowledgeBaseRepository _knowledgeBaseRepository;
    private readonly IDocumentRepository _documentRepository;
    private readonly IDocumentChunkRepository _chunkRepository;
    private readonly IEmbeddingService _embeddingService;
    private readonly RagAIDbContext _context;
    private readonly ILogger<DataSeederService> _logger;

    public DataSeederService(
        IKnowledgeBaseRepository knowledgeBaseRepository,
        IDocumentRepository documentRepository,
        IDocumentChunkRepository chunkRepository,
        IEmbeddingService embeddingService,
        RagAIDbContext context,
        ILogger<DataSeederService> logger)
    {
        _knowledgeBaseRepository = knowledgeBaseRepository;
        _documentRepository = documentRepository;
        _chunkRepository = chunkRepository;
        _embeddingService = embeddingService;
        _context = context;
        _logger = logger;
    }

    /// <summary>
    /// 添加测试知识库数据
    /// </summary>
    public async Task SeedKnowledgeBaseAsync()
    {
        try
        {
            _logger.LogInformation("开始添加测试知识库数据...");

            // 创建或获取测试用户
            var testUserId = Guid.Parse("00000000-0000-0000-0000-000000000001");
            var existingUser = await _context.Users.FindAsync(testUserId);

            if (existingUser == null)
            {
                var testUser = new Users
                {
                    Id = testUserId,
                    UserName = "test_user",
                    Email = "test@example.com",
                    Password = "test_password", // 在实际应用中应该是加密的密码
                    CreatedBy = testUserId,
                    UpdatedBy = testUserId
                };

                _context.Users.Add(testUser);
                await _context.SaveChangesAsync();
                _logger.LogInformation("创建测试用户: test_user");
            }

            // 获取用户引用
            var userReference = existingUser ?? await _context.Users.FindAsync(testUserId);
            if (userReference == null)
            {
                throw new InvalidOperationException("无法找到测试用户");
            }

            // 创建测试文档
            var testDocument = new Documents
            {
                Id = Guid.NewGuid(),
                Title = "AI知识库测试文档",
                FileName = "ai_knowledge_test.txt",
                FilePath = "test/ai_knowledge_test.txt",
                FileType = ".txt",
                FileSize = "15.2 KB",
                Description = "人工智能相关知识测试数据",
                Tags = "AI,测试,知识库",
                AccessLevel = "internal",
                Status = "completed",
                UserId = testUserId, // 设置UserId外键
                User = userReference, // 设置User导航属性
                CreatedBy = testUserId,
                UpdatedBy = testUserId
            };

            await _documentRepository.CreateAsync(testDocument);
            _logger.LogInformation($"创建测试文档: {testDocument.Title}");

            // 测试知识数据
            var knowledgeData = new[]
            {
                new { Content = "人工智能（AI）是计算机科学的一个分支，旨在创建能够执行通常需要人类智能的任务的系统。AI系统可以学习、推理、感知环境并做出决策。", Title = "人工智能定义", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "机器学习是人工智能的核心技术之一，通过算法让计算机从数据中学习模式，无需明确编程即可执行特定任务。主要包括监督学习、无监督学习和强化学习。", Title = "机器学习概述", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "深度学习是机器学习的一个子集，使用多层神经网络来模拟人脑的工作方式。它在图像识别、语音识别和自然语言处理方面取得了突破性进展。", Title = "深度学习原理", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "自然语言处理（NLP）是AI的一个重要分支，专注于让计算机理解、解释和生成人类语言。包括文本分析、语言翻译、情感分析等技术。", Title = "自然语言处理", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "计算机视觉使计算机能够从图像或视频中获取有意义的信息。主要技术包括图像分类、目标检测、图像分割和人脸识别等。", Title = "计算机视觉技术", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "神经网络是深度学习的基础，由相互连接的节点（神经元）组成，能够学习复杂的数据模式。包括卷积神经网络（CNN）和循环神经网络（RNN）等类型。", Title = "神经网络结构", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "强化学习是机器学习的一种方法，通过与环境交互来学习最优策略。智能体通过试错和奖励机制来改进其行为，广泛应用于游戏AI和机器人控制。", Title = "强化学习方法", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "大语言模型（LLM）如GPT、BERT等，通过在大规模文本数据上预训练，能够理解和生成自然语言。它们在对话系统、文本生成和知识问答方面表现出色。", Title = "大语言模型", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "AI伦理涉及人工智能系统的公平性、透明度、隐私保护和安全性。随着AI技术的发展，确保AI系统的负责任使用变得越来越重要。", Title = "AI伦理考虑", DocumentType = ".txt", EmbeddingType = "text-embedding" },
                new { Content = "边缘计算与AI结合，将AI推理能力部署在靠近数据源的设备上，减少延迟并提高隐私保护。这在物联网和实时应用中特别有价值。", Title = "边缘AI技术", DocumentType = ".txt", EmbeddingType = "text-embedding" }
            };

            for (int i = 0; i < knowledgeData.Length; i++)
            {
                var data = knowledgeData[i];

                // 创建文档块
                var chunk = new DocumentChunks
                {
                    Id = Guid.NewGuid(),
                    ChunkIndex = i,
                    Content = data.Content,
                    TokenCount = EstimateTokenCount(data.Content),
                    Document = testDocument,
                    CreatedBy = testDocument.CreatedBy,
                    UpdatedBy = testDocument.UpdatedBy
                };

                await _chunkRepository.CreateAsync(chunk);

                // 生成向量嵌入
                _logger.LogInformation($"生成向量嵌入 {i + 1}/10: {data.Title}");
                var embedding = await _embeddingService.GenerateTextEmbeddingAsync(data.Content);

                // 创建知识库条目
                var knowledgeBase = new KnowledgeBase
                {
                    Id = Guid.NewGuid(),
                    Embedding = embedding,
                    ChunkId = chunk.Id,
                    Content = data.Content,
                    DocumentType = data.DocumentType,
                    EmbeddingType = data.EmbeddingType,
                    IsChunked = true,
                    Source = "seeder",
                    Title = data.Title,
                    CreatedBy = testDocument.CreatedBy,
                    UpdatedBy = testDocument.UpdatedBy
                };

                await _knowledgeBaseRepository.CreatedAsync(knowledgeBase);
                _logger.LogInformation($"成功添加知识库条目 {i + 1}/10: {data.Title}");

                // 添加短暂延迟以避免API限制
                await Task.Delay(500);
            }

            _logger.LogInformation("成功添加10条测试知识库数据！");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "添加测试知识库数据时发生错误");
            throw;
        }
    }

    /// <summary>
    /// 检查是否已有测试数据
    /// </summary>
    public async Task<bool> HasTestDataAsync()
    {
        var testDocs = await _documentRepository.GetAllAsync();
        return testDocs.Any(d => d.Title.Contains("测试") || d.Description?.Contains("测试") == true);
    }

    /// <summary>
    /// 清理测试数据
    /// </summary>
    public async Task CleanupTestDataAsync()
    {
        try
        {
            _logger.LogInformation("开始清理测试数据...");

            var testDocs = await _documentRepository.GetAllAsync();
            var testDocsToDelete = testDocs.Where(d => d.Title.Contains("测试") || d.Description?.Contains("测试") == true).ToList();

            foreach (var doc in testDocsToDelete)
            {
                await _documentRepository.DeleteAsync(doc.Id);
                _logger.LogInformation($"删除测试文档: {doc.Title}");
            }

            _logger.LogInformation("测试数据清理完成");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "清理测试数据时发生错误");
            throw;
        }
    }

    private int EstimateTokenCount(string text)
    {
        // 简单的token估算，通常1个token约等于0.75个单词
        var words = text.Split(new[] { ' ', '\t', '\n', '\r', '，', '。', '、' }, StringSplitOptions.RemoveEmptyEntries);
        return (int)(words.Length * 1.33);
    }
}
